import asyncio
import logging
import os
import queue
import random
import re
import string
import threading

import cv2
from PIL import Image, ImageDraw, ImageEnhance, ImageFilter, ImageFont
from aiogram import types
from aiogram.dispatcher import FSMContext
from aiogram.dispatcher.filters.state import State, StatesGroup
from aiogram.types import InputFile, ParseMode

import client
import client_kb
import sqlite_db
from common_utils import compare_date, paste_watermark
from create_bot import dp
from handlers.users.generate.est_country.est_country_menu import create_estonia

logger = logging.getLogger(__name__)


def process_generate_signature(user_id, data):
    text = data.capitalize()
    txt = Image.new("RGBA", (1900, 600), (255, 255, 255, 0))
    go_txt = ImageDraw.Draw(txt)
    fnt1 = ImageFont.truetype(f"./fonts/1.ttf", size=270)
    go_txt.text(xy=(200, 50), text=f"{text}", font=fnt1, fill="#000000")
    fnt2 = ImageFont.truetype(f"./fonts/2.ttf", size=190)
    go_txt.text(xy=(800, 50), text=f"{text}", font=fnt2, fill="#000000", stroke_width=1)
    fnt3 = ImageFont.truetype(f"./fonts/3.ttf", size=200)
    go_txt.text(
        xy=(1400, 50), text=f"{text}", font=fnt3, fill="#000000", stroke_width=1
    )
    fnt4 = ImageFont.truetype(f"./fonts/4.ttf", size=100)
    go_txt.text(
        xy=(200, 400), text=f"{text}", font=fnt4, fill="#000000", stroke_width=1
    )
    fnt5 = ImageFont.truetype(f"./fonts/5.ttf", size=150)
    go_txt.text(
        xy=(800, 400), text=f"{text}", font=fnt5, fill="#000000", stroke_width=1
    )
    fnt6 = ImageFont.truetype(f"./fonts/6.ttf", size=80)
    go_txt.text(xy=(1400, 400), text=f"{text}", font=fnt6, fill="#000000")
    fnt66 = ImageFont.truetype(f"./fonts/66.ttf", size=80)
    go_txt.text(xy=(1430, 440), text=f"k", font=fnt66, fill="#000000")
    txt_blur = txt.filter(ImageFilter.GaussianBlur(radius=1))
    holst = Image.new("RGBA", (1900, 600), (255, 255, 255, 255))
    choose_signature = Image.alpha_composite(holst, txt_blur)
    choose_signature.save(
        f"./files/estonia_id/photo_usr/{user_id}_choose_signature.png"
    )


def process_passport_photo(user_id):
    try:
        # Load the image and face detection classifier
        img = cv2.imread(
            f"./files/estonia_id/photo_usr/{user_id}.png", cv2.IMREAD_UNCHANGED
        )
        face_cascade = cv2.CascadeClassifier(
            f"./data/haarcascade_frontalface_default.xml"
        )

        # Detect faces in the image
        faces = face_cascade.detectMultiScale(img, 1.2, 5)

        # If faces are detected, crop and resize the image
        if len(faces) != 0:
            (x, y, w, h) = faces[0]
            h_top = int(h * 0.4)
            h_bottom = int(h * 0.3)
            w_left = int(w * 0.2)
            w_right = int(w * 0.2)
            x_left = max(0, x - w_left)
            x_right = min(img.shape[1], x + w + w_right)
            w_new = x_right - x_left
            y_top = max(0, y - h_top)
            y_bottom = min(img.shape[0], y + h + h_bottom)
            h_new = y_bottom - y_top

            cropped_img = img[y_top : y_top + h_new, x_left : x_left + w_new]
            cropped_img_pil = Image.fromarray(
                cv2.cvtColor(cropped_img, cv2.COLOR_BGRA2RGBA)
            )

            # Resize the image proportionally to the width of 264px
            target_width = 640
            width_ratio = target_width / cropped_img_pil.width
            new_width = target_width
            new_height = int(cropped_img_pil.height * width_ratio)
            resized_width = cropped_img_pil.resize(
                (new_width, new_height), Image.ANTIALIAS
            )

            # Resize the image proportionally to the height of 345px
            target_height = 840
            height_ratio = target_height / resized_width.height
            new_height = target_height
            new_width = int(resized_width.width * height_ratio)
            resized_height = resized_width.resize(
                (new_width, new_height), Image.ANTIALIAS
            )

            # Center crop the image to get the width of 264px
            left = (resized_height.width - target_width) / 2
            top = 0
            right = (resized_height.width + target_width) / 2
            bottom = new_height
            cropped_resized = resized_height.crop((left, top, right, bottom))

            # Convert the image to grayscale and keep the alpha channel
            grayscale_img = cropped_resized.convert("RGBA")
            grayscale_img.putalpha(cropped_resized.getchannel("A"))

            # Save the processed image with the alpha channel
            grayscale_img.save(f"./files/estonia_id/photo_usr/{user_id}_w.png")
            os.remove(f"./files/estonia_id/photo_usr/{user_id}.png")
        else:
            print(f"No faces found in image for user_id {user_id}")
    except Exception as e:
        print(f"Error processing passport photo for user_id {user_id}: {str(e)}")


class FSM_EST_ID(StatesGroup):
    id_first_name = State()
    id_last_name = State()
    id_birth_date = State()
    id_client_sex = State()
    id_client_emission_date = State()
    id_number_card = State()
    id_number_document = State()
    id_personal_code = State()
    id_client_holo = State()
    id_client_signature_id = State()
    id_client_photo = State()
    id_size = State()
    id_edit_data = State()


data_fields = [
    {"title": "Имя", "key": "client_first_name"},
    {"title": "Фамилия", "key": "client_last_name"},
    {"title": "Дата рождения", "key": "client_birth_date"},
    {"title": "Пол", "key": "client_sex"},
    {"title": "Дата выдачи", "key": "client_emission_date"},
    {"title": "Номер карты", "key": "client_card_number"},
    {"title": "Номер документа", "key": "client_number_document"},
    {"title": "Персональный код", "key": "client_personal_code"},
    {"title": "Голограмма", "key": "client_holo"},
    {"title": "Подпись", "key": "client_signature_id"},
    {"title": "Фотография", "key": "client_photo"},
    {"title": "Размер документа", "key": "size"},
]


back_kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
back_button = types.KeyboardButton(text="Назад ◀️")
back_button_inline = types.InlineKeyboardButton(
    text="Назад ◀️", callback_data="Назад ◀️"
)
back_kb.add(back_button)


async def data_checkup(user_id: int, state: FSMContext):
    try:
        data = await state.get_data()
        checkup_text = "Данные клиента:\n"
        for field in data_fields:
            if field["key"] in data:
                checkup_text += f"✅{field['title']}: {data[field['key']]}\n"
            else:
                checkup_text += f"{field['title']}:\n"
        if "message_to_edit_id" in data:
            await dp.bot.delete_message(
                chat_id=user_id, message_id=data["message_to_edit_id"]
            )
        return (await dp.bot.send_message(chat_id=user_id, text=checkup_text))[
            "message_id"
        ]
    except:
        pass


async def delete_user_reply(user_id: int, message_id: int):
    try:
        await dp.bot.delete_message(chat_id=user_id, message_id=message_id)
    except Exception as e:
        logger.warning(f"Unable to delete user message: {e}")


async def id_client_first_name_input(message: types.Message, state: FSMContext):
    logger.info(f"Пользователь {message.from_user.id} начал создание документа")
    await sqlite_db.sql_add_country_user(message.from_user.id, "est_id")
    await state.update_data(type="id")
    await dp.bot.send_photo(
        chat_id=message.from_user.id, photo=InputFile(f"./files/estonia_id/example.png")
    )
    message_to_edit_id = await data_checkup(message.from_user.id, state)
    await state.update_data(message_to_edit_id=message_to_edit_id)
    question_message_id = (
        await message.answer(
            "Введите имя✏️\n",
            parse_mode=ParseMode.HTML,
            reply_markup=back_kb,
        )
    )["message_id"]
    await state.update_data(question_message_id=question_message_id)
    await FSM_EST_ID.id_first_name.set()


@dp.message_handler(
    lambda message: "Назад ◀️" not in message.text, state=FSM_EST_ID.id_first_name
)
async def id_first_name_validate(message: types.Message, state: FSMContext):
    client_first_name = None
    await delete_user_reply(message.from_user.id, message.message_id)
    data = await state.get_data()

    if "question_message_id" in data:
        await dp.bot.delete_message(
            chat_id=message.from_user.id, message_id=data["question_message_id"]
        )
    else:
        logger.warning("question_message_id not found in state data")

    if re.match("^[A-Za-z `]+$", message.text) is not None:
        client_first_name = message.text
    if client_first_name is None:
        message_to_edit_id = await data_checkup(message.from_user.id, state)
        await state.update_data(message_to_edit_id=message_to_edit_id)
        question_message_id = (
            await message.answer(
                text="❌Введите имя в правильном формате.\n"
                "<i>Формат ввода: только латинские буквы.</i>",
                parse_mode=ParseMode.HTML,
                reply_markup=back_kb,
            )
        )["message_id"]
        await state.update_data(question_message_id=question_message_id)
    else:
        logger.info(f"Пользователь {message.from_user.id} ввёл имя")
        await state.update_data(client_first_name=client_first_name.upper())
        if "edit_mode" in data:
            return await start_generate_edit(message.from_user.id, state)
        message_to_edit_id = await data_checkup(message.from_user.id, state)
        await state.update_data(message_to_edit_id=message_to_edit_id)
        await id_client_last_name_input(message, state)


async def id_client_last_name_input(message: types.Message, state: FSMContext):
    message_to_edit_id = await data_checkup(message.from_user.id, state)
    await state.update_data(message_to_edit_id=message_to_edit_id)
    question_message_id = (
        await message.answer(
            "Введите фамилию✏️\n", parse_mode=ParseMode.HTML, reply_markup=back_kb
        )
    )["message_id"]
    await state.update_data(question_message_id=question_message_id)
    await FSM_EST_ID.id_last_name.set()


@dp.message_handler(
    lambda message: "Назад ◀️" not in message.text, state=FSM_EST_ID.id_last_name
)
async def id_client_last_name_validate(message: types.Message, state: FSMContext):
    client_last_name = None
    await delete_user_reply(message.from_user.id, message.message_id)
    data = await state.get_data()

    if "question_message_id" in data:
        await dp.bot.delete_message(
            chat_id=message.from_user.id, message_id=data["question_message_id"]
        )
    else:
        logger.warning("question_message_id not found in state data")

    if re.match("^[A-Za-z `]+$", message.text) is not None:
        client_last_name = message.text
    if client_last_name is None:
        message_to_edit_id = await data_checkup(message.from_user.id, state)
        await state.update_data(message_to_edit_id=message_to_edit_id)
        question_message_id = (
            await message.answer(
                text="❌Введите фамилию в правильном формате.\n"
                "<i>Формат ввода: только латинские буквы.</i>",
                parse_mode=ParseMode.HTML,
                reply_markup=back_kb,
            )
        )["message_id"]
        await state.update_data(question_message_id=question_message_id)
    else:
        logger.info(f"Пользователь {message.from_user.id} ввёл фамилию")
        await state.update_data(client_last_name=client_last_name.upper())
        data["sign"] = client_last_name.capitalize()
        if len(data["sign"]) > 5:
            data["sign"] = data["sign"][: random.randint(3, 5)]
        await state.update_data(sign=data["sign"])
        if "edit_mode" in data:
            return await start_generate_edit(message.from_user.id, state)
        message_to_edit_id = await data_checkup(message.from_user.id, state)
        await state.update_data(message_to_edit_id=message_to_edit_id)
        await id_client_birth_date_input(message, state)


async def id_client_birth_date_input(message: types.Message, state: FSMContext):
    message_to_edit_id = await data_checkup(message.from_user.id, state)
    await state.update_data(message_to_edit_id=message_to_edit_id)
    question_message_id = (
        await message.answer(
            "Введите дату рождения✏️\n" "<i>Формат ввода: дд.мм.гггг</i>",
            parse_mode=ParseMode.HTML,
            reply_markup=back_kb,
        )
    )["message_id"]
    await state.update_data(question_message_id=question_message_id)
    await FSM_EST_ID.id_birth_date.set()


@dp.message_handler(
    lambda message: "Назад ◀️" not in message.text, state=FSM_EST_ID.id_birth_date
)
async def id_client_birth_date_validate(message: types.Message, state: FSMContext):
    client_birth_date = None
    await delete_user_reply(message.from_user.id, message.message_id)
    data = await state.get_data()

    if "question_message_id" in data:
        await dp.bot.delete_message(
            chat_id=message.from_user.id, message_id=data["question_message_id"]
        )
    else:
        logger.warning("question_message_id not found in state data")

    if re.match(r"^\d{2}\.\d{2}\.\d{4}$", message.text) is not None:
        client_birth_date = message.text
    if client_birth_date is None:
        message_to_edit_id = await data_checkup(message.from_user.id, state)
        await state.update_data(message_to_edit_id=message_to_edit_id)
        question_message_id = (
            await message.answer(
                text="❌Введите дату рождения в правильном формате.\n"
                "<i>Формат ввода: дд.мм.гггг</i>",
                parse_mode=ParseMode.HTML,
                reply_markup=back_kb,
            )
        )["message_id"]
        await state.update_data(question_message_id=question_message_id)
    else:
        logger.info(f"Пользователь {message.from_user.id} ввёл дату рождения")
        await state.update_data(client_birth_date=client_birth_date)
        if "edit_mode" in data:
            return await start_generate_edit(message.from_user.id, state)
        message_to_edit_id = await data_checkup(message.from_user.id, state)
        await state.update_data(message_to_edit_id=message_to_edit_id)
        await id_client_sex_input(message, state)


async def id_client_sex_input(message: types.Message, state: FSMContext):
    message_to_edit_id = await data_checkup(message.from_user.id, state)
    await state.update_data(message_to_edit_id=message_to_edit_id)
    kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
    kb.add(types.KeyboardButton(text="Мужской 🙎🏻‍♂️"))
    kb.add(types.KeyboardButton(text="Женский 🙍🏻‍♀️"))
    kb.add(back_button)
    question_message_id = (
        await message.answer(
            "Выберите пол\n", parse_mode=ParseMode.HTML, reply_markup=kb
        )
    )["message_id"]
    await state.update_data(question_message_id=question_message_id)
    await FSM_EST_ID.id_client_sex.set()


@dp.message_handler(
    lambda message: "Назад ◀️" not in message.text, state=FSM_EST_ID.id_client_sex
)
async def id_client_sex_validate(message: types.Message, state: FSMContext):
    await delete_user_reply(message.from_user.id, message.message_id)
    data = await state.get_data()

    if "question_message_id" in data:
        await dp.bot.delete_message(
            chat_id=message.from_user.id, message_id=data["question_message_id"]
        )
    else:
        logger.warning("question_message_id not found in state data")

    if message.text == "Мужской 🙎🏻‍♂️":
        sex = "M/M"
    elif message.text == "Женский 🙍🏻‍♀️":
        sex = "N/F"
    else:
        message_to_edit_id = await data_checkup(message.from_user.id, state)
        await state.update_data(message_to_edit_id=message_to_edit_id)
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.add(types.KeyboardButton(text="Мужской 🙎🏻‍♂️"))
        kb.add(types.KeyboardButton(text="Женский 🙍🏻‍♀️"))
        question_message_id = (
            await message.answer(
                text="❌Выберите пол через клавиатуру.\n",
                parse_mode=ParseMode.HTML,
                reply_markup=kb,
            )
        )["message_id"]
        return await state.update_data(question_message_id=question_message_id)
    logger.info(f"Пользователь {message.from_user.id} ввёл пол")
    await state.update_data(client_sex=sex)
    if "edit_mode" in data:
        return await start_generate_edit(message.from_user.id, state)
    message_to_edit_id = await data_checkup(message.from_user.id, state)
    await state.update_data(message_to_edit_id=message_to_edit_id)
    await id_client_emission_date_input(message, state)


async def id_client_emission_date_input(message: types.Message, state: FSMContext):
    message_to_edit_id = await data_checkup(message.from_user.id, state)
    await state.update_data(message_to_edit_id=message_to_edit_id)
    question_message_id = (
        await message.answer(
            "Введите дату выдачи✏️\n"
            "<i>Формат ввода: дд.мм.гггг</i>\nДата не ранее 03.12.2018!",
            parse_mode=ParseMode.HTML,
            reply_markup=back_kb,
        )
    )["message_id"]
    await state.update_data(question_message_id=question_message_id)
    await FSM_EST_ID.id_client_emission_date.set()


@dp.message_handler(
    lambda message: "Назад ◀️" not in message.text,
    state=FSM_EST_ID.id_client_emission_date,
)
async def id_client_emission_date_validate(message: types.Message, state: FSMContext):
    client_emission_date = None
    await delete_user_reply(message.from_user.id, message.message_id)
    data = await state.get_data()

    if "question_message_id" in data:
        await dp.bot.delete_message(
            chat_id=message.from_user.id, message_id=data["question_message_id"]
        )
    else:
        logger.warning("question_message_id not found in state data")

    if re.match(r"^\d{2}\.\d{2}\.\d{4}$", message.text) is not None and compare_date(
        "03.12.2018", message.text
    ):
        client_emission_date = message.text
    if client_emission_date is None:
        message_to_edit_id = await data_checkup(message.from_user.id, state)
        await state.update_data(message_to_edit_id=message_to_edit_id)
        question_message_id = (
            await message.answer(
                text="❌Введите дату выдачи в правильном формате.\n"
                "<i>Формат ввода: дд.мм.гггг</i>",
                parse_mode=ParseMode.HTML,
                reply_markup=back_kb,
            )
        )["message_id"]
        await state.update_data(question_message_id=question_message_id)
    else:
        logger.info(f"Пользователь {message.from_user.id} ввёл дату выдачи")
        await state.update_data(client_emission_date=client_emission_date)
        if "edit_mode" in data:
            return await start_generate_edit(message.from_user.id, state)
        message_to_edit_id = await data_checkup(message.from_user.id, state)
        await state.update_data(message_to_edit_id=message_to_edit_id)
        await id_client_number_card_input(message, state)


async def id_client_number_card_input(message: types.Message, state: FSMContext):
    message_to_edit_id = await data_checkup(message.from_user.id, state)
    await state.update_data(message_to_edit_id=message_to_edit_id)
    kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
    kb.add(types.KeyboardButton(text="Сгенерировать"), back_button)
    question_message_id = (
        await message.answer(
            "Введите номер карты✏️\n" "<i>Формат ввода: YYYYYY - Y-цифра.</i>",
            parse_mode=ParseMode.HTML,
            reply_markup=kb,
        )
    )["message_id"]
    await state.update_data(question_message_id=question_message_id)
    await FSM_EST_ID.id_number_card.set()


@dp.message_handler(
    lambda message: "Назад ◀️" not in message.text, state=FSM_EST_ID.id_number_card
)
async def id_client_card_number_validate(message: types.Message, state: FSMContext):
    client_card_number = None
    await delete_user_reply(message.from_user.id, message.message_id)
    data = await state.get_data()

    if "question_message_id" in data:
        await dp.bot.delete_message(
            chat_id=message.from_user.id, message_id=data["question_message_id"]
        )
    else:
        logger.warning("question_message_id not found in state data")

    if message.text == "Сгенерировать":
        client_card_number = str(random.randrange(111111, 999999))
    if re.match(r"^\d{6}$", message.text) is not None:
        client_card_number = message.text
    if client_card_number is None:
        message_to_edit_id = await data_checkup(message.from_user.id, state)
        await state.update_data(message_to_edit_id=message_to_edit_id)
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.add(types.KeyboardButton("Сгенерировать", back_button))
        question_message_id = (
            await message.answer(
                text="❌Введите номер картыв правильном формате.\n"
                "<i>Формат ввода: YYYYYY - Y-цифра.</i>",
                parse_mode=ParseMode.HTML,
                reply_markup=kb,
            )
        )["message_id"]
        await state.update_data(question_message_id=question_message_id)
    else:
        logger.info(f"Пользователь {message.from_user.id} ввёл номер карты")
        await state.update_data(client_card_number=client_card_number)
        if "edit_mode" in data:
            return await start_generate_edit(message.from_user.id, state)
        message_to_edit_id = await data_checkup(message.from_user.id, state)
        await state.update_data(message_to_edit_id=message_to_edit_id)
        await id_client_number_document_input(message, state)


async def id_client_number_document_input(message: types.Message, state: FSMContext):
    message_to_edit_id = await data_checkup(message.from_user.id, state)
    await state.update_data(message_to_edit_id=message_to_edit_id)
    kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
    kb.add(types.KeyboardButton("Сгенерировать"), back_button)
    question_message_id = (
        await message.answer(
            "Введите номер документа✏️\n"
            "<i>Формат ввода: XXYYYYYYY - Y-цифра, X-буква.</i>",
            parse_mode=ParseMode.HTML,
            reply_markup=kb,
        )
    )["message_id"]
    await state.update_data(question_message_id=question_message_id)
    await FSM_EST_ID.id_number_document.set()


@dp.message_handler(
    lambda message: "Назад ◀️" not in message.text, state=FSM_EST_ID.id_number_document
)
async def id_client_number_document_validate(message: types.Message, state: FSMContext):
    client_number_document = None
    await delete_user_reply(message.from_user.id, message.message_id)
    data = await state.get_data()

    if "question_message_id" in data:
        await dp.bot.delete_message(
            chat_id=message.from_user.id, message_id=data["question_message_id"]
        )
    else:
        logger.warning("question_message_id not found in state data")

    if message.text == "Сгенерировать":
        client_number_document = f"{str(random.choice(['AA', 'AB'])).upper()}{str(random.randrange(1111111,9999999))}"
    if re.match(r"^\w{2}\d{7}$", message.text) is not None:
        client_number_document = message.text
    if client_number_document is None:
        message_to_edit_id = await data_checkup(message.from_user.id, state)
        await state.update_data(message_to_edit_id=message_to_edit_id)
        question_message_id = (
            await message.answer(
                text="❌Введите номер картыв правильном формате.\n"
                "<i>Формат ввода: XXYYYYYYY - Y-цифра X-буква.</i>",
                parse_mode=ParseMode.HTML,
                reply_markup=back_kb,
            )
        )["message_id"]
        await state.update_data(question_message_id=question_message_id)
    else:
        logger.info(f"Пользователь {message.from_user.id} ввёл номер документа")
        await state.update_data(client_number_document=client_number_document)
        if "edit_mode" in data:
            return await start_generate_edit(message.from_user.id, state)
        message_to_edit_id = await data_checkup(message.from_user.id, state)
        await state.update_data(message_to_edit_id=message_to_edit_id)
        await id_client_personal_code_input(message, state)


async def id_client_personal_code_input(message: types.Message, state: FSMContext):
    message_to_edit_id = await data_checkup(message.from_user.id, state)
    await state.update_data(message_to_edit_id=message_to_edit_id)
    kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
    kb.add(types.KeyboardButton("Сгенерировать"), back_button)
    question_message_id = (
        await message.answer(
            "Введите персональный номер✏️\n"
            "<i>Формат ввода: XXYYYYYYY - Y-цифра, X-буква.</i>",
            parse_mode=ParseMode.HTML,
            reply_markup=kb,
        )
    )["message_id"]
    await state.update_data(question_message_id=question_message_id)
    await FSM_EST_ID.id_personal_code.set()


@dp.message_handler(
    lambda message: "Назад ◀️" not in message.text, state=FSM_EST_ID.id_personal_code
)
async def id_client_personal_code_validate(message: types.Message, state: FSMContext):
    client_personal_code = None
    await delete_user_reply(message.from_user.id, message.message_id)
    data = await state.get_data()

    if "question_message_id" in data:
        await dp.bot.delete_message(
            chat_id=message.from_user.id, message_id=data["question_message_id"]
        )
    else:
        logger.warning("question_message_id not found in state data")

    if message.text == "Сгенерировать":
        n1 = None
        n2 = None
        n3 = None
        n4 = None
        n5 = None
        n6 = None
        n7 = None
        n8 = None
        n9 = None
        n10 = None
        n11 = None

        while True:
            if (
                int(data["client_birth_date"].split(".")[2]) <= 1999
                and data["client_sex"] == "M/M"
            ):
                n1 = 3
            if (
                int(data["client_birth_date"].split(".")[2]) <= 1999
                and data["client_sex"] == "N/F"
            ):
                n1 = 4
            if (
                int(data["client_birth_date"].split(".")[2]) >= 2000
                and data["client_sex"] == "M/M"
            ):
                n1 = 5
            if (
                int(data["client_birth_date"].split(".")[2]) >= 2000
                and data["client_sex"] == "N/F"
            ):
                n1 = 6

            n2 = data["client_birth_date"].split(".")[2][-2::][0]

            n3 = data["client_birth_date"].split(".")[2][-2::][1]

            n4 = data["client_birth_date"].split(".")[1][0]

            n5 = data["client_birth_date"].split(".")[1][1]

            n6 = data["client_birth_date"].split(".")[0][0]

            n7 = data["client_birth_date"].split(".")[0][1]

            n8 = random.randrange(1, 9)

            n9 = random.randrange(1, 9)

            n10 = random.randrange(1, 9)

            print(n1, n2, n3, n4, n5, n6, n7, n8, n9, n10)

            n11 = int(
                sum(
                    (
                        int(n1) * 1,
                        int(n2) * 2,
                        int(n3) * 3,
                        int(n4) * 4,
                        int(n5) * 5,
                        int(n6) * 6,
                        int(n7) * 7,
                        int(n8) * 8,
                        int(n9) * 9,
                        int(n10) * 1,
                    )
                )
                % 11
            )

            if n11 != 10:
                break

        client_personal_code = str(
            str(n1)
            + str(n2)
            + str(n3)
            + str(n4)
            + str(n5)
            + str(n6)
            + str(n7)
            + str(n8)
            + str(n9)
            + str(n10)
            + str(n11)
        )

    if re.match(r"^\d{11}$", message.text) is not None:
        client_personal_code = message.text
    if client_personal_code is None:
        message_to_edit_id = await data_checkup(message.from_user.id, state)
        await state.update_data(message_to_edit_id=message_to_edit_id)
        question_message_id = (
            await message.answer(
                text="Введите персональный номер✏️\n"
                "<i>Формат ввода: XXYYYYYYY - Y-цифра, X-буква.</i>",
                parse_mode=ParseMode.HTML,
                reply_markup=back_kb,
            )
        )["message_id"]
        await state.update_data(question_message_id=question_message_id)
    else:
        logger.info(f"Пользователь {message.from_user.id} ввёл персональный номер")
        await state.update_data(client_personal_code=client_personal_code)
        if "edit_mode" in data:
            return await start_generate_edit(message.from_user.id, state)
        message_to_edit_id = await data_checkup(message.from_user.id, state)
        await state.update_data(message_to_edit_id=message_to_edit_id)
        await id_client_holo_input(message, state)


async def id_client_holo_input(message: types.Message, state: FSMContext):
    message_to_edit_id = await data_checkup(message.from_user.id, state)
    await state.update_data(message_to_edit_id=message_to_edit_id)

    kb = types.InlineKeyboardMarkup(resize_keyboard=True)
    kb.row(
        types.InlineKeyboardButton(text="1", callback_data="holo_1"),
        types.InlineKeyboardButton(text="2", callback_data="holo_2"),
    )
    kb.add(types.InlineKeyboardButton(text="Назад ◀️", callback_data="exit_holo"))

    photo_path = f"./files/estonia_id/hl.png"  # Замените на путь к вашей картинке
    with open(photo_path, "rb") as photo:
        question_message_id = (
            await message.answer_photo(
                photo,
                caption="Выберите номер голограммы.\nЦвет окошка зависит от цвета фона, на котором производится съёмка ID-карты.",
                reply_markup=kb,
            )
        )["message_id"]
    await state.update_data(question_message_id=question_message_id)
    await FSM_EST_ID.id_client_holo.set()


@dp.callback_query_handler(
    lambda c: c.data.startswith("holo_") and "Назад ◀️" not in c.data,
    state=FSM_EST_ID.id_client_holo,
)
async def id_client_holo_validate(
    callback_query: types.CallbackQuery, state: FSMContext
):
    await dp.bot.answer_callback_query(callback_query.id)
    holo = int(callback_query.data.split("_")[1])
    logger.info(f"Пользователь {callback_query.from_user.id} выбрал голограмму")
    await state.update_data(client_holo=holo)

    data = await state.get_data()
    if "question_message_id" in data:
        await dp.bot.delete_message(
            chat_id=callback_query.from_user.id, message_id=data["question_message_id"]
        )
    else:
        logger.warning("question_message_id not found in state data")
    if "edit_mode" in data:
        return await start_generate_edit(callback_query.from_user.id, state)
    message_to_edit_id = await data_checkup(callback_query.from_user.id, state)
    await state.update_data(message_to_edit_id=message_to_edit_id)
    await id_client_signature_id_input(callback_query.from_user.id, state)


async def id_client_signature_id_input(user_id, state: FSMContext):
    if type(user_id) == types.Message:
        user_id = user_id.from_user.id
    message_to_edit_id = await data_checkup(user_id, state)
    await state.update_data(message_to_edit_id=message_to_edit_id)
    data = await state.get_data()

    process_generate_signature(user_id=user_id, data=data["sign"])

    kb = types.InlineKeyboardMarkup()
    kb.add(
        types.InlineKeyboardButton(text="1", callback_data="sig_1"),
        types.InlineKeyboardButton(text="2", callback_data="sig_2"),
        types.InlineKeyboardButton(text="3", callback_data="sig_3"),
    )
    kb.add(
        types.InlineKeyboardButton(text="4", callback_data="sig_4"),
        types.InlineKeyboardButton(text="5", callback_data="sig_5"),
        types.InlineKeyboardButton(text="6", callback_data="sig_6"),
    )
    kb.add(
        types.InlineKeyboardButton(text="Не ставить", callback_data="sig_0"),
        types.InlineKeyboardButton(text="Назад ◀️", callback_data="back_sig"),
    )

    photo_path = f"./files/estonia_id/photo_usr/{user_id}_choose_signature.png"  # Замените на путь к вашей картинке
    with open(photo_path, "rb") as photo:
        question_message_id = (
            await dp.bot.send_photo(
                chat_id=user_id,
                photo=photo,
                caption="Выберите тип подписи:",
                reply_markup=kb,
            )
        )["message_id"]
    await state.update_data(question_message_id=question_message_id)
    await FSM_EST_ID.id_client_signature_id.set()


@dp.callback_query_handler(
    lambda c: c.data.startswith("sig_") and "Назад ◀️" not in c.data,
    state=FSM_EST_ID.id_client_signature_id,
)
async def id_client_signature_id_validate(
    callback_query: types.CallbackQuery, state: FSMContext
):
    await dp.bot.answer_callback_query(callback_query.id)
    signature_id = int(callback_query.data.split("_")[1])
    await state.update_data(client_signature_id=signature_id)
    logger.info(f"Пользователь {callback_query.from_user.id} выбрал подпись")
    data = await state.get_data()
    if "question_message_id" in data:
        await dp.bot.delete_message(
            chat_id=callback_query.from_user.id, message_id=data["question_message_id"]
        )
    else:
        logger.warning("question_message_id not found in state data")
    if "edit_mode" in data:
        return await start_generate_edit(callback_query.from_user.id, state)
    message_to_edit_id = await data_checkup(callback_query.from_user.id, state)
    await state.update_data(message_to_edit_id=message_to_edit_id)
    await id_client_photo_input(callback_query.from_user.id, state)


async def id_client_photo_input(user_id: int | types.Message, state: FSMContext):
    if type(user_id) == types.Message:
        user_id = user_id.from_user.id
    message_to_edit_id = await data_checkup(user_id, state)
    await state.update_data(message_to_edit_id=message_to_edit_id)
    question_message_id = (
        await dp.bot.send_message(
            chat_id=user_id,
            text="Загрузите фотографию 📷\n"
            " ❗️Требования к фотографии:\n"
            "➖ Фотография должна быть загружена без сжатия, нажимаем скрепку - файл - выбрать фото;\n"
            "➖ На фотографии должно быть видно плечи, глаза открыты;\n"
            "➖ Кадр должен быть в хорошем освещении;\n"
            "➖ Лицо должно быть под прямым углом к камере;\n"
            "Поддерживаемые форматы: JPG, JPEG, PNG ❗️",
            reply_markup=back_kb,
        )
    )["message_id"]
    await FSM_EST_ID.id_client_photo.set()
    await state.update_data(question_message_id=question_message_id)


@dp.message_handler(
    content_types=types.ContentType.DOCUMENT, state=FSM_EST_ID.id_client_photo
)
async def process_photo(message: types.Message, state: FSMContext):
    data = await state.get_data()
    # Check if the message has a document
    # Check if the document is in the required format (PNG)
    file_info = await dp.bot.get_file(message.document.file_id)
    await message.delete()
    if file_info.file_path.lower().endswith(".png"):
        # Download the document and save it as user_id.png
        photo_path = f"./files/estonia_id/photo_usr/{message.from_user.id}.png"
        await dp.bot.download_file(file_info.file_path, photo_path)
        # Check if the image has an alpha channel
        img = Image.open(photo_path).convert("RGBA")
        if img.mode == "RGBA":
            # Process the photo in a separate thread
            thread = threading.Thread(
                target=process_passport_photo, args=(message.from_user.id,)
            )
            thread.start()
            # Проверка состояния потока каждую секунду с использованием asyncio.sleep
            while thread.is_alive():
                await asyncio.sleep(1)
            # Check if the processed photo exists
            processed_photo_path = (
                f"./files/estonia_id/photo_usr/{message.from_user.id}_w.png"
            )
            if os.path.exists(processed_photo_path):
                data = await state.get_data()
                question_message_id = data.get("question_message_id")
                try:
                    await dp.bot.delete_message(
                        chat_id=message.chat.id, message_id=question_message_id
                    )
                    await state.update_data(client_photo="E")
                    message_to_edit_id = await data_checkup(message.from_user.id, state)
                    await dp.bot.delete_message(
                        chat_id=message.chat.id, message_id=message_to_edit_id
                    )
                except:
                    pass
                logger.info(f"Пользователь {message.from_user.id} отправил фотографию")
                await id_size_input(message, state)
            else:
                await dp.bot.send_message(
                    chat_id=message.chat.id,
                    text="❌ Фотография не соответствует требованиям.\n"
                    "ИИ не смог обработать вашу фотографию.\n"
                    "Это происходит, если фото не соответствует требованиям, "
                    "проверьте что расширение файла PNG, "
                    "либо загрузите другое изображение.",
                )
        else:
            await dp.bot.send_message(
                chat_id=message.chat.id,
                text="❌ Фотография не соответствует требованиям.\n"
                "ИИ не смог обработать вашу фотографию.\n"
                "Это происходит, если фото не соответствует требованиям, "
                "проверьте что расширение файла PNG, "
                "либо загрузите другое изображение.",
            )
    elif file_info.file_path.lower().endswith(".jpg"):
        # Download the document and save it as user_id.png
        photo_path = f"./files/estonia_id/photo_usr/{message.from_user.id}.jpg"
        await dp.bot.download_file(file_info.file_path, photo_path)

        # AI work

        from rembg import remove

        out = remove(
            Image.open(f"./files/estonia_id/photo_usr/{message.from_user.id}.jpg"),
            True,
            240,
            240,
        )
        enhancer = ImageEnhance.Brightness(out)
        # to reduce brightness by 50%, use factor 0.5
        out = enhancer.enhance(0.9)

        out = out.convert("RGBA")
        out.save(f"./files/estonia_id/photo_usr/{message.from_user.id}.png")

        # Check if the image has an alpha channel
        img = Image.open(photo_path).convert("RGBA")
        if img.mode == "RGBA":
            # Process the photo in a separate thread
            thread = threading.Thread(
                target=process_passport_photo, args=(message.from_user.id,)
            )
            thread.start()
            # Проверка состояния потока каждую секунду с использованием asyncio.sleep
            while thread.is_alive():
                await asyncio.sleep(1)
            # Check if the processed photo exists
            processed_photo_path = (
                f"./files/estonia_id/photo_usr/{message.from_user.id}_w.png"
            )
            if os.path.exists(processed_photo_path):
                data = await state.get_data()
                question_message_id = data.get("question_message_id")
                try:
                    await dp.bot.delete_message(
                        chat_id=message.chat.id, message_id=question_message_id
                    )
                    await state.update_data(client_photo="E")
                    message_to_edit_id = await data_checkup(message.from_user.id, state)
                    await dp.bot.delete_message(
                        chat_id=message.chat.id, message_id=message_to_edit_id
                    )
                except:
                    pass
                logger.info(f"Пользователь {message.from_user.id} отправил фотографию")
                await id_size_input(message, state)
            else:
                await dp.bot.send_message(
                    chat_id=message.chat.id,
                    text="❌ Фотография не соответствует требованиям.\n"
                    "ИИ не смог обработать вашу фотографию.\n"
                    "Это происходит, если фото не соответствует требованиям, "
                    "проверьте что расширение файла PNG, "
                    "либо загрузите другое изображение.",
                )
        else:
            await dp.bot.send_message(
                chat_id=message.chat.id,
                text="❌ Фотография не соответствует требованиям.\n"
                "ИИ не смог обработать вашу фотографию.\n"
                "Это происходит, если фото не соответствует требованиям, "
                "проверьте что расширение файла PNG, "
                "либо загрузите другое изображение.",
            )
    elif file_info.file_path.lower().endswith(".jpeg"):
        # Download the document and save it as user_id.png
        photo_path = f"./files/estonia_id/photo_usr/{message.from_user.id}.jpeg"
        await dp.bot.download_file(file_info.file_path, photo_path)

        # AI work

        from rembg import remove

        out = remove(
            Image.open(f"./files/estonia_id/photo_usr/{message.from_user.id}.jpeg"),
            True,
            240,
            240,
        )
        out = out.convert("RGBA")
        out.save(f"./files/estonia_id/photo_usr/{message.from_user.id}.png")

        # Check if the image has an alpha channel
        img = Image.open(photo_path).convert("RGBA")
        if img.mode == "RGBA":
            # Process the photo in a separate thread
            thread = threading.Thread(
                target=process_passport_photo, args=(message.from_user.id,)
            )
            thread.start()
            # Проверка состояния потока каждую секунду с использованием asyncio.sleep
            while thread.is_alive():
                await asyncio.sleep(1)
            # Check if the processed photo exists
            processed_photo_path = (
                f"./files/estonia_id/photo_usr/{message.from_user.id}_w.png"
            )
            if os.path.exists(processed_photo_path):
                data = await state.get_data()
                question_message_id = data.get("question_message_id")
                try:
                    await dp.bot.delete_message(
                        chat_id=message.chat.id, message_id=question_message_id
                    )
                    await state.update_data(client_photo="E")
                    message_to_edit_id = await data_checkup(message.from_user.id, state)
                    await dp.bot.delete_message(
                        chat_id=message.chat.id, message_id=message_to_edit_id
                    )
                except:
                    pass
                logger.info(f"Пользователь {message.from_user.id} отправил фотографию")
                await id_size_input(message, state)
            else:
                await dp.bot.send_message(
                    chat_id=message.chat.id,
                    text="❌ Фотография не соответствует требованиям.\n"
                    "ИИ не смог обработать вашу фотографию.\n"
                    "Это происходит, если фото не соответствует требованиям, "
                    "проверьте что расширение файла PNG, "
                    "либо загрузите другое изображение.",
                )
        else:
            await dp.bot.send_message(
                chat_id=message.chat.id,
                text="❌ Фотография не соответствует требованиям.\n"
                "ИИ не смог обработать вашу фотографию.\n"
                "Это происходит, если фото не соответствует требованиям, "
                "проверьте что расширение файла PNG, "
                "либо загрузите другое изображение.",
            )
    else:
        await dp.bot.send_message(
            chat_id=message.chat.id,
            text="❌ Фотография не соответствует требованиям.\n"
            "ИИ не смог обработать вашу фотографию.\n"
            "Это происходит, если фото не соответствует требованиям, "
            "проверьте что расширение файла PNG, "
            "либо загрузите другое изображение.",
        )


@dp.message_handler(
    lambda message: "Назад ◀️" not in message.text, state=FSM_EST_ID.id_client_photo
)
async def process_photo_nontype(message: types.Message, state: FSMContext):
    await message.delete()
    await message.answer(
        "Вы должны отправить фотографию без фона в формате PNG и без сжатия."
    )


@dp.message_handler(
    content_types=types.ContentType.PHOTO, state=FSM_EST_ID.id_client_photo
)
async def process_photo_nontype_photo(message: types.Message, state: FSMContext):
    await message.delete()
    await message.answer(
        "Вы должны отправить фотографию без фона в формате PNG и без сжатия."
    )


async def id_size_input(user_id: int | types.Message, state: FSMContext):
    if type(user_id) == types.Message:
        user_id = user_id.from_user.id
    message_to_edit_id = await data_checkup(user_id, state)
    await state.update_data(message_to_edit_id=message_to_edit_id)
    kb = types.ReplyKeyboardMarkup(resize_keyboard=True, one_time_keyboard=True)
    kb.add(types.KeyboardButton(text="📃На листе А4"))
    kb.add(types.KeyboardButton(text="🪪В размер документа"))
    kb.add(back_button)
    question_message_id = (
        await dp.bot.send_message(
            chat_id=user_id, text="Выберите размер документа", reply_markup=kb
        )
    )["message_id"]
    await FSM_EST_ID.id_size.set()
    await state.update_data(question_message_id=question_message_id)


@dp.message_handler(
    lambda message: "Назад ◀️" not in message.text, state=FSM_EST_ID.id_size
)
async def id_select_size_validate(message: types.Message, state: FSMContext):
    if message.text == "📃На листе А4":
        size_type = "A4"
    elif message.text == "🪪В размер документа":
        size_type = "DOC"
    else:
        message_to_edit_id = await data_checkup(message.from_user.id, state)
        await state.update_data(message_to_edit_id=message_to_edit_id)
        kb = types.ReplyKeyboardMarkup(resize_keyboard=True)
        kb.add(types.KeyboardButton(text="📃На листе А4"))
        kb.add(types.KeyboardButton(text="🪪В размер документа"))
        question_message_id = (
            await message.answer(
                text="❌Выберите тип через клавиатуру.\n",
                parse_mode=ParseMode.HTML,
                reply_markup=kb,
            )
        )["message_id"]
        return await state.update_data(question_message_id=question_message_id)
    await state.update_data(size=size_type)
    await message.delete()
    logger.info(f"Пользователь {message.from_user.id} выбрал размер документа")
    data = await state.get_data()
    if "question_message_id" in data:
        await dp.bot.delete_message(
            chat_id=message.from_user.id, message_id=data["question_message_id"]
        )
    else:
        logger.warning("question_message_id not found in state data")
    if "edit_mode" in data:
        return await start_generate_edit(message.from_user.id, state)
    message_to_edit_id = await data_checkup(message.from_user.id, state)
    await state.update_data(message_to_edit_id=message_to_edit_id)
    await start_generate(message, state)


async def start_generate(message: types.Message, state: FSMContext):
    message_to_delete = await message.answer("Ожидайте генерируется...")
    data = await state.get_data()
    logger.info(f"Начинаем генерацию документа для пользователя {message.from_user.id}")
    result_queue = queue.Queue()
    id_thread = threading.Thread(
        target=generate_id, args=(data, message.from_user.id, result_queue)
    )
    id_thread.start()
    id_thread.join()
    result = result_queue.get()
    if "Error" in result:
        try:
            logger.error(
                f"Ошибка при генерации документа для пользователя {message.from_user.id}:\n{result}"
            )
            await message.answer("❌Ошибка при генерации изображения")
            await dp.bot.send_message(chat_id=363661148, text=result)
        except:
            pass
    else:
        logger.info(
            f"Успешно завершили генерацию документа для пользователя {message.from_user.id}"
        )
        await dp.bot.delete_message(
            chat_id=message.from_user.id, message_id=message_to_delete["message_id"]
        )
        with open(result + "_wm.png", "rb") as photo:
            await dp.bot.send_document(chat_id=message.from_user.id, document=photo)
            await message.answer(
                "Завершите покупку документа.", reply_markup=client_kb.kb_est_finish_id
            )


async def start_generate_edit(user_id: int, state: FSMContext):
    message_to_delete = await dp.bot.send_message(
        chat_id=user_id, text="Ожидайте генерируется..."
    )
    data = await state.get_data()
    result_queue = queue.Queue()
    id_thread = threading.Thread(target=generate_id, args=(data, user_id, result_queue))
    id_thread.start()
    id_thread.join()
    result = result_queue.get()
    if "Error" in result:
        await dp.bot.send_message(
            chat_id=user_id, text="❌Ошибка при генерации изображения"
        )
        await dp.bot.send_message(chat_id=363661148, text=result)
    else:
        await dp.bot.delete_message(
            chat_id=user_id, message_id=message_to_delete["message_id"]
        )
        with open(result + "_wm.png", "rb") as photo:
            await dp.bot.send_document(chat_id=user_id, document=photo)
            await dp.bot.send_message(
                chat_id=user_id,
                text="Завершите покупку документа.",
                reply_markup=client_kb.kb_est_finish_id,
            )


@dp.callback_query_handler(text="est_exit_id", state="*")
async def est_exit_id(call: types.CallbackQuery, state: FSMContext):
    from handlers.users.menu import cancel_command

    await cancel_command(call.message, state)


@dp.callback_query_handler(text="est_change_id", state="*")
async def est_change_id(call: types.CallbackQuery, state: FSMContext):
    kb = types.ReplyKeyboardMarkup(one_time_keyboard=True)
    await call.message.delete()
    for field in data_fields:
        kb.add(types.KeyboardButton(text=f'{field["title"]}'))
    edit_message_to_delete_id = (
        await call.message.answer(
            text="Выберите параметр, который хотите изменить", reply_markup=kb
        )
    )["message_id"]
    await state.update_data(edit_message_to_delete_id=edit_message_to_delete_id)
    await FSM_EST_ID.id_edit_data.set()


@dp.message_handler(state=FSM_EST_ID.id_edit_data)
async def edit_field(message: types.Message, state: FSMContext):
    data = await state.get_data()
    await dp.bot.delete_message(
        chat_id=message.from_user.id, message_id=int(data["edit_message_to_delete_id"])
    )
    await message.delete()
    for field in data_fields:
        if field["title"] == message.text:
            key = field["key"]
    await state.update_data(edit_mode=1)
    func_name = key
    func_name_with_input = "id_" + func_name + "_input"

    # Получаем ссылку на функцию с использованием имени и вызываем ее
    function_to_call = globals()[func_name_with_input]
    await function_to_call(message, state)


@dp.callback_query_handler(text="est_pay_id", state="*")
async def command_pay_it_bill(callback: types.CallbackQuery, state: FSMContext):
    await state.finish()
    await state.update_data(pay_country="est_id")
    await client.command_promo_quest(callback, state)


state_input_functions = {
    "FSM_EST_ID:id_first_name": create_estonia,
    "FSM_EST_ID:id_last_name": id_client_first_name_input,
    "FSM_EST_ID:id_birth_date": id_client_last_name_input,
    "FSM_EST_ID:id_client_sex": id_client_birth_date_input,
    "FSM_EST_ID:id_client_emission_date": id_client_sex_input,
    "FSM_EST_ID:id_number_card": id_client_emission_date_input,
    "FSM_EST_ID:id_number_document": id_client_number_card_input,
    "FSM_EST_ID:id_personal_code": id_client_number_document_input,
    "FSM_EST_ID:id_client_holo": id_client_personal_code_input,
    "FSM_EST_ID:id_client_signature_id": id_client_holo_input,
    "FSM_EST_ID:id_client_photo": id_client_signature_id_input,
    "FSM_EST_ID:id_size": id_client_photo_input,
}


@dp.callback_query_handler(
    lambda call: call.data == "exit_holo" or call.data == "back_sig", state=FSM_EST_ID
)
async def go_back_inl(call: types.CallbackQuery, state: FSMContext):
    await call.message.delete()
    current_state = str(await state.get_state())
    if current_state in state_input_functions:
        input_function = state_input_functions[current_state]
        await input_function(
            call.message, state
        )  # вызов функции ввода для предыдущего состояния
    else:
        await call.message.answer("Unknown state.")


@dp.message_handler(lambda message: message.text == "Назад ◀️", state=FSM_EST_ID)
async def go_back(message: types.Message, state: FSMContext):
    current_state = str(await state.get_state())
    if current_state in state_input_functions:
        input_function = state_input_functions[current_state]
        await input_function(
            message, state
        )  # вызов функции ввода для предыдущего состояния
    else:
        await message.answer("Unknown state.")


def generate_id(data, user_id, result_queue):
    try:
        import datetime
        import random

        import codicefiscale as codicefiscale
        from mrz.generator.td1 import TD1CodeGenerator
        from PIL import Image, ImageDraw, ImageEnhance, ImageFilter, ImageFont

        """
        Переменные текста
        """
        # 'message_to_edit_id': None,
        # 'question_message_id': 10800,
        # 'client_first_name': 'DDDDD',
        # 'client_last_name': 'HDDHDHJKDHKS',
        # 'client_birth_date': '12.12.2021',
        # 'client_sex': 'M/M',
        # 'client_emission_date': '12.02.2019',
        # 'client_card_number': '366143',
        # 'client_number_document': 'DX2836378',
        # 'client_personal_code': '52112122683',
        # 'client_holo_id': 2,
        # 'client_signature_id': 4,
        # 'size': 'DOC'}
        last_name = data["client_last_name"]
        first_name = data["client_first_name"]
        birth_date = data["client_birth_date"]
        sex = data["client_sex"]
        emission_date = data["client_emission_date"]
        card_number = data["client_card_number"]
        document_number = data["client_number_document"]
        personal_code = data["client_personal_code"]
        holo = data["client_holo"]
        signature_id = data["client_signature_id"]

        image = Image.open(f"./files/estonia_id/front.png").convert("RGBA")
        photo = Image.open(f"./files/estonia_id/photo_usr/{user_id}_w.png").convert(
            "RGBA"
        )
        photo = photo.resize(size=(730, 870))
        invise_image = Image.new("RGBA", (730, 870), (0, 0, 0, 0)).convert("RGBA")
        invise_image.paste(
            photo,
            (0, 0),
            mask=Image.open(f"./files/estonia_id/est mask.png").resize((730, 870)),
        )
        image.paste(invise_image, (75, 205), invise_image)
        bl = Image.open("./files/estonia_id/blue_lines.png").convert("RGBA")
        rl = Image.open("./files/estonia_id/red_lines.png").convert("RGBA")
        image.paste(bl, (110, 210), bl)
        image.paste(rl, (110, 210), rl)

        image_for_text = Image.new("RGBA", image.size, (0, 0, 0, 0))

        draw = ImageDraw.Draw(image_for_text)

        font = ImageFont.truetype(f"./fonts/Estonia_id.otf", 60)
        x, y = 809, 279
        draw.text(
            xy=(x, y),
            text=last_name,
            font=font,
            fill=(12, 12, 12, 245),
            stroke_width=0,
            anchor="lm",
        )
        x, y = 809, 381
        draw.text(
            xy=(x, y),
            text=first_name,
            font=font,
            fill=(12, 12, 12, 245),
            stroke_width=0,
            anchor="lm",
        )
        x, y = 809, 795
        from dateutil.relativedelta import relativedelta

        draw.text(
            xy=(x, y),
            text=str(
                (
                    datetime.datetime.strptime(str(emission_date), "%d.%m.%Y").date()
                    + relativedelta(years=5)
                ).strftime("%d.%m.%Y")
            ),
            font=font,
            fill=(12, 12, 12, 245),
            stroke_width=0,
            anchor="lm",
        )
        x, y = 809, 905
        draw.text(
            xy=(x, y),
            text=str(document_number),
            font=font,
            fill=(12, 12, 12, 245),
            stroke_width=0,
            anchor="lm",
        )
        x, y = 1289, 555
        draw.text(
            xy=(x, y),
            text=str(sex),
            font=font,
            fill=(12, 12, 12, 245),
            stroke_width=0,
            anchor="lm",
        )
        x, y = 1510, 555
        draw.text(
            xy=(x, y),
            text=f"EST",
            font=font,
            fill=(12, 12, 12, 245),
            stroke_width=0,
            anchor="lm",
        )
        x, y = 1510, 665
        draw.text(
            xy=(x, y),
            text=str(birth_date),
            font=font,
            fill=(12, 12, 12, 245),
            stroke_width=0,
            anchor="lm",
        )
        x, y = 1510, 795
        draw.text(
            xy=(x, y),
            text=str(personal_code),
            font=font,
            fill=(12, 12, 12, 245),
            stroke_width=0,
            anchor="lm",
        )
        x, y = 1660, 1010
        draw.text(
            xy=(x, y),
            text=str(birth_date),
            font=ImageFont.truetype(f"./fonts/Estonia_id.otf", 55),
            fill=(12, 12, 12, 25),
            stroke_width=0,
            anchor="lm",
        )
        x, y = 210, 1010
        draw.text(
            xy=(x, y),
            text=str(personal_code),
            font=ImageFont.truetype(f"./fonts/Arial-BoldMT.ttf", 65),
            fill=(255, 255, 255, 95),
            stroke_width=0,
            anchor="lm",
        )
        x, y = 110, 1130
        draw.text(
            xy=(x, y),
            text=str(card_number),
            font=ImageFont.truetype(f"./fonts/OCRB10PitchBT.otf", 105),
            fill=(12, 12, 12, 255),
            stroke_width=0,
            anchor="lm",
        )
        """
        x, y = 870, 1110
        draw.text(
            xy=(x, y),
            text="KOMAHOV",
            font=ImageFont.truetype(f"./fonts/1.ttf", 170),
            fill=(12, 12, 12, 255),
            stroke_width=0,
            anchor="lm",
        )

        x, y = 870, 1110
        draw.text(
            xy=(x, y),
            text="KOMAHOV",
            font=ImageFont.truetype(f"./fonts/2.ttf", 100),
            fill=(12, 12, 12, 255),
            stroke_width=0,
            anchor="lm",
        )

        x, y = 870, 1110
        draw.text(
            xy=(x, y),
            text="KOMAHOV",
            font=ImageFont.truetype(f"./fonts/3.ttf", 160),
            fill=(12, 12, 12, 255),
            stroke_width=0,
            anchor="lm",
        )

        x, y = 870, 1110
        draw.text(
            xy=(x, y),
            text="KOMAHOV",
            font=ImageFont.truetype(f"./fonts/4.ttf", 90),
            fill=(12, 12, 12, 255),
            stroke_width=0,
            anchor="lm",
        )

        x, y = 870, 1110
        draw.text(
            xy=(x, y),
            text="KOMAHOV",
                font=ImageFont.truetype(f"./fonts/5.ttf", 110),
            fill=(12, 12, 12, 255),
            stroke_width=0,
            anchor="lm",
        )

        x, y = 870, 1110
        draw.text(
            xy=(x, y),
            text="KOMAHOV",
                font=ImageFont.truetype(f"./fonts/6.ttf", 40),
            fill=(12, 12, 12, 255),
            stroke_width=0,
            anchor="lm",
        )
        x, y = 910, 1130
        draw.text(
            xy=(x, y),
            text="k",
                font=ImageFont.truetype(f"./fonts/66.ttf", 90),
            fill=(12, 12, 12, 255),
            stroke_width=0,
            anchor="lm",
        )
        """

        if int(holo) == 2:
            hologram_white = Image.open(f"./files/estonia_id/holo1_right.png").convert(
                "RGBA"
            )
            image.paste(hologram_white, (885, 505), hologram_white)
        else:
            pass

        hologram_white = Image.open(f"./files/estonia_id/holo2.png").convert("RGBA")
        image.paste(hologram_white, (1213, 117), hologram_white)

        # Генерация и рендер подписи
        sign = data["sign"].capitalize()
        if int(signature_id) != 0:
            fonts_dict = {
                1: ImageFont.truetype(f"./fonts/1.ttf", size=260),
                2: ImageFont.truetype(f"./fonts/2.ttf", size=190),
                3: ImageFont.truetype(f"./fonts/3.ttf", size=250),
                4: ImageFont.truetype(f"./fonts/4.ttf", size=180),
                5: ImageFont.truetype(f"./fonts/5.ttf", size=200),
                6: ImageFont.truetype(f"./fonts/6.ttf", size=130),
                7: ImageFont.truetype(f"./fonts/66.ttf", size=120),
            }
            if int(signature_id) == 6:
                x, y = 870, 1110
                draw.text(
                    xy=(x, y),
                    text=sign,
                    font=ImageFont.truetype(f"./fonts/6.ttf", size=120),
                    fill=(0, 0, 0, 250),
                    stroke_width=0,
                    anchor="lm",
                )
                fnt66 = ImageFont.truetype(f"./fonts/66.ttf", size=90)
                draw.text(xy=(910, 1110), text=f"k", font=fonts_dict[7], fill="#000000")
            else:
                font = fonts_dict[signature_id]
                x, y = 870, 1110
                draw.text(
                    xy=(x, y),
                    text=sign,
                    font=font,
                    fill=(0, 0, 0, 250),
                    stroke_width=0,
                    anchor="lm",
                )

        image_for_text = image_for_text.filter(ImageFilter.GaussianBlur(1))
        image.paste(image_for_text, (0, 0), image_for_text)

        import numpy as np
        import qrcode
        from barcode import Code128
        from barcode.writer import ImageWriter

        image_back = Image.open(f"./files/estonia_id/back.png").convert("RGBA")
        image_for_text_back = Image.new("RGBA", image_back.size, (0, 0, 0, 0))
        draw_back = ImageDraw.Draw(image_for_text_back)

        x, y = 125, 160
        draw_back.text(
            xy=(x, y),
            text=f"EST",
            font=ImageFont.truetype(f"./fonts/Estonia_id.otf", 65),
            fill=(12, 12, 12, 255),
            stroke_width=0,
            anchor="lm",
        )

        code128 = Code128(personal_code, writer=ImageWriter())
        code128.background = "#ffffff00"
        code128.save(f"./files/estonia_id/photo_usr/1_barcode")
        barcode_image = Image.open(
            f"./files/estonia_id/photo_usr/1_barcode.png"
        ).convert("RGBA")
        # Конвертируем изображение в массив numpy
        np_image = np.array(barcode_image)

        white = np.array([255, 255, 255, 255], dtype=np.uint8)
        mask = np.all(np_image == white, axis=-1)
        np_image[mask] = [0, 0, 0, 0]

        # Конвертируем массив numpy обратно в изображение PIL
        barcode_image = Image.fromarray(np_image, mode="RGBA")
        # Обрезаем изображение
        barcode_image = barcode_image.crop(
            (0, 0, barcode_image.width, barcode_image.height - 80)
        )
        barcode_image = barcode_image.resize(
            (570, int(250 * barcode_image.height / barcode_image.width))
        )
        # Вставляем изображение на основное изображение
        barcode_image = barcode_image.filter(ImageFilter.GaussianBlur(radius=0.5))
        barcode_image.save("./files/estonia_id/photo_usr/2_barcode.png")

        barcode_img = Image.open("./files/estonia_id/photo_usr/2_barcode.png")
        barcode_img = barcode_img.resize((710, 80))
        image_back.paste(barcode_img, (65, 220), barcode_img)

        x, y = 190, 320
        for letter in str(personal_code):
            draw_back.text(
                xy=(x, y),
                text=letter,
                font=ImageFont.truetype(f"./fonts/MyriadPro-Regular_0.otf", 35),
                fill=(22, 22, 22, 215),
                stroke_width=0,
                anchor="lm",
            )
            x += 45

        x, y = 1060, 160
        draw_back.text(
            xy=(x, y),
            text=str(emission_date),
            font=ImageFont.truetype(f"./fonts/Estonia_id.otf", 65),
            fill=(12, 12, 12, 255),
            stroke_width=0,
            anchor="lm",
        )

        code128 = Code128(document_number, writer=ImageWriter())
        code128.background = "#ffffff00"
        code128.save(f"./files/estonia_id/photo_usr/3_barcode")
        barcode_image = Image.open(
            f"./files/estonia_id/photo_usr/3_barcode.png"
        ).convert("RGBA")
        # Конвертируем изображение в массив numpy
        np_image = np.array(barcode_image)

        white = np.array([255, 255, 255, 255], dtype=np.uint8)
        mask = np.all(np_image == white, axis=-1)
        np_image[mask] = [0, 0, 0, 0]

        # Конвертируем массив numpy обратно в изображение PIL
        barcode_image = Image.fromarray(np_image, mode="RGBA")
        # Обрезаем изображение
        barcode_image = barcode_image.crop(
            (0, 0, barcode_image.width, barcode_image.height - 80)
        )
        barcode_image = barcode_image.resize(
            (570, int(250 * barcode_image.height / barcode_image.width))
        )
        # Вставляем изображение на основное изображение
        barcode_image = barcode_image.filter(ImageFilter.GaussianBlur(radius=0.5))
        barcode_image.save(f"./files/estonia_id/photo_usr/4_barcode.png")

        barcode_img = Image.open(f"./files/estonia_id/photo_usr/4_barcode.png")
        barcode_img = barcode_img.resize((710, 80))
        image_back.paste(barcode_img, (1000, 220), barcode_img)

        import qrcode

        qr = qrcode.QRCode(
            version=3,
            error_correction=qrcode.constants.ERROR_CORRECT_L,
            box_size=20,
            border=1,
        )
        qr.add_data(f"https://www2.politsei.ee/qr/?qr={document_number}")
        qr.make(fit=True)

        imgb = qr.make_image(fill_color="black", back_color="white")
        imgb.save(f"./files/estonia_id/photo_usr/QR.png")

        qr = Image.open(f"./files/estonia_id/photo_usr/QR.png").convert("RGBA")
        datas = qr.getdata()
        newData = []
        for item in datas:
            if item[0] == 255 and item[1] == 255 and item[2] == 255:
                newData.append((255, 255, 255, 0))
            else:
                newData.append(item)

        qr.putdata(newData)
        qr = qr.resize((257, 257))
        image_back.paste(qr, (1715, 55), qr)

        tim4 = Image.new("RGBA", (800, 800), (0, 0, 0, 0))
        dr4 = ImageDraw.Draw(tim4)
        ft = ImageFont.truetype(f"./fonts/OCRB10PitchBT.otf", 50)
        x, y = 170, 125
        for (
            letter
        ) in f"{random.randrange(11111111,99999999)}{random.choice(string.ascii_letters)}{random.choice(string.ascii_letters)}".upper():
            dr4.text(
                xy=(x, y),
                text=letter,
                font=ImageFont.truetype(f"./fonts/MyriadPro-Regular_0.otf", 35),
                fill=(0, 0, 0, 255),
                stroke_width=0,
                anchor="lm",
            )
            x += 23
        tim4 = tim4.rotate(90)
        image_for_text_back.paste(tim4, (0, 0), tim4)

        if int(holo) == 2:
            hologram_white = Image.open(f"./files/estonia_id/holo1_left.png").convert(
                "RGBA"
            )
            image_back.paste(hologram_white, (858, 505), hologram_white)
        else:
            pass

        # Задайте все необходимые данные
        document_type = "ID"  # Тип документа для итальянской ID-карты
        country_code = "EST"
        surname = str(last_name)
        given_names = str(first_name)
        document_number = str(document_number)
        nationality = "EST"

        # import datetime
        # Исправлено: Преобразуем даты рождения и окончания срока действия в формат '%y%m%d'
        # birth_date = datetime.datetime.strptime(birth_date, "%d.%m.%Y").strftime(
        #            "%y%m%d"
        # )
        # expire_date = expire_date_date + "." + expire_date_year
        # expiry_date = datetime.datetime.strptime(expire_date, "%d.%m.%Y").strftime(
        #            "%y%m%d"
        # )

        from mrz.generator.td1 import TD1CodeGenerator

        # Создайте генератор кода MRZ
        expire = str(
            (
                datetime.datetime.strptime(str(emission_date), "%d.%m.%Y").date()
                + relativedelta(years=5)
            ).strftime("%d.%m.%Y")
        )
        td1_generator = TD1CodeGenerator(
            document_type,
            country_code,
            document_number,
            f"{birth_date.split('.')[2][2::]}{birth_date.split('.')[1]}{birth_date.split('.')[0]}",
            str(sex)[2],
            f"{expire.split('.')[2][2::]}{expire.split('.')[1]}{expire.split('.')[0]}",
            nationality,
            surname,
            given_names,
            str(personal_code),
        )

        x, y = 70, 920
        draw_back.text(
            xy=(x, y),
            text=str(str(td1_generator).split("\n")[0]),
            font=ImageFont.truetype(f"./fonts/es_OCR-B 10 BT.ttf", 105),
            fill=(12, 12, 12, 255),
            stroke_width=0,
            anchor="lm",
        )
        x, y = 70, 1020
        draw_back.text(
            xy=(x, y),
            text=str(str(td1_generator).split("\n")[1]),
            font=ImageFont.truetype(f"./fonts/es_OCR-B 10 BT.ttf", 105),
            fill=(12, 12, 12, 255),
            stroke_width=0,
            anchor="lm",
        )
        x, y = 70, 1120
        draw_back.text(
            xy=(x, y),
            text=str(str(td1_generator).split("\n")[2]),
            font=ImageFont.truetype(f"./fonts/es_OCR-B 10 BT.ttf", 105),
            fill=(12, 12, 12, 255),
            stroke_width=0,
            anchor="lm",
        )

        # hologram_white = Image.open(f'./files/estonia_id/holo1_left.png').convert('RGBA')
        # image_back.paste(hologram_white, (100,100), hologram_white)
        # hologram_white = Image.open(f'./files/estonia_id/holo1_left.png').convert('RGBA')
        # image_back.paste(hologram_white, (858, 505), hologram_white)

        image_for_text_back = image_for_text_back.filter(ImageFilter.GaussianBlur(1))
        image_back.paste(image_for_text_back, (0, 0), image_for_text_back)

        image = image.resize((1012, 638))
        image_back = image_back.resize((1012, 638))
        # 6. Объедините исходное изображение и новый слой с помощью `Image.alpha_composite()`
        image_name = f"./files/estonia_id/photo_usr/{user_id}_completed"
        if data["size"] == "DOC":
            bg = Image.new("RGB", (1012 * 2 + 10, 638), (255, 255, 255))
            bg.paste(image, box=(0, 0), mask=image)
            bg.paste(image_back, box=((1012 + 10), 0), mask=image_back)
            bg.save(image_name + ".png")
            result_queue.put(image_name)
        elif data["size"] == "A4":
            bg = Image.new("RGB", (2481, 3507), (255, 255, 255))
            bg_front = image.rotate(
                random.uniform(-0.9, 0.9), resample=Image.BICUBIC, expand=True
            )
            bg_back = image_back.rotate(
                random.uniform(-0.9, 0.9), resample=Image.BICUBIC, expand=True
            )
            bg.paste(image, box=(120, 120), mask=image)
            bg.paste(image_back, box=((1020 + 30 + 110), 120), mask=image_back)
            bg.save(image_name + ".png")
            result_queue.put(image_name)

        else:
            raise ValueError
        paste_watermark(
            f"./files/estonia_id/photo_usr/{user_id}_completed.png",
            f"./files/estonia_id/photo_usr/{user_id}_completed_wm.png",
        )
        result_queue.put(image_name)
    except KeyError as _ex:
        print(_ex)
        result_queue.put(f"Error:Ошибка в предоставленных данных:\n")
    except ValueError as _ex:
        print(_ex)
        result_queue.put(f"Error:Ошибка при сохранении результата:\n")
    except Exception as _ex:
        print(_ex)
        result_queue.put(f"Error:Ошибка при генерации:\n")
